﻿using FtpTestTool.model;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace FtpTestTool
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private FtpPortModel ftp = new FtpPortModel();

        private void Form1_Load(object sender, EventArgs e)
        {
            showInput();
        }

        /// <summary>
        /// 重置
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnClean_Click(object sender, EventArgs e)
        {
            ftp.StopFlag = true;
            Thread.Sleep(1000);
        }

        private async void btnStart_Click(object sender, EventArgs e)
        {
            try
            {
                hiddenInput();
                rtbOutput.Clear();

                int iTime = 0;
                if (!int.TryParse(txtNumber.Text, out iTime))
                {
                    txtNumber.Focus();
                    return;
                }

                ftp.ftps.Clear();
                ftp.ExeTimes = iTime;
                ftp.UsePassive = btnFtpUsePassive.Checked;
                ftp.StopFlag = false;

                if (string.IsNullOrEmpty(txtAccount.Text))
                {
                    txtAccount.Focus();
                    return;
                }
                if (string.IsNullOrEmpty(txtPasswd.Text))
                {
                    txtPasswd.Focus();
                    return;
                }
                if (string.IsNullOrEmpty(txtIp.Text))
                {
                    txtIp.Focus();
                    return;
                }
                if (string.IsNullOrEmpty(txtPort.Text))
                {
                    txtPort.Focus();
                    return;
                }

                if (string.IsNullOrEmpty(txtFileFolder.Text))
                {
                    rtbOutput.AppendText("请选择您要用于测试文件所在文件夹");
                    return;
                }

                int port = 21;
                if (!int.TryParse(txtPort.Text, out port))
                {
                    return;
                }
                ftp.ftps.Add(new FtpPortInfo { Ip = txtIp.Text, Port = port, Uid = txtAccount.Text, Pwd = txtPasswd.Text });
                ftp.FileFolderPath = txtFileFolder.Text;

                testFtp();

            }
            catch (Exception ex)
            {

            }
        }

        /// <summary>
        /// 选择文件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            btnOpenFolder.Description = "请选择常用办公文档进行测试";
            var dialog = btnOpenFolder.ShowDialog();
            if (dialog == DialogResult.OK)
            {
                txtFileFolder.Text = btnOpenFolder.SelectedPath;
            }
            else
            {
                txtFileFolder.Text = "";
            }
        }

        private async void testFtp()
        {
            await Task.Run(() =>
            {
                hideOrShowCtrl(false);

                Stopwatch swTotal = new Stopwatch();
                var iTotalFile = 0;
                var soureDir = ftp.FileFolderPath;
                var testUrl = @"{0}\ftptest\{1}\";
                using (FtpClient client = FtpResourceHelper.Instance.getFtpClient(ftp.ftps.FirstOrDefault(), ftp.UsePassive))
                {
                    List<string> listDelFiles = new List<string>();
                    var dirPath = string.Format(testUrl, Environment.CurrentDirectory, DateTime.Now.ToString("yyyy-MM-dd"));
                    var tagPath = string.Format(testUrl, "", DateTime.Now.ToString("yyyy-MM-dd") + "\\" + DateTime.Now.Ticks).Replace("\\", "/");


                    var sources = Directory.GetFiles(soureDir).ToList();
                    iTotalFile = sources.Count;
                    var iSort = 0;
                    long totalSize = 0;
                    swTotal.Start();
                    bool isBreak = false;

                    var mst = client.CheckAndCreateDirectory(tagPath);
                    if (mst.State != RequestResultType.Ok)
                    {
                        setUploadResult(mst.Message);
                        if (mst.Message == "无法连接到远程服务器")
                        {
                            isBreak = true;
                        }
                    }
                    if (!isBreak)
                    {
                        sources.ForEach(c =>
                        {
                            if (ftp.StopFlag)
                            {
                                return;
                            }
                            var file = new FileInfo(c);
                            var fileSize = file.Length;
                            file = null;
                            totalSize += fileSize * ftp.ExeTimes;
                            iSort++;
                            for (var iCnt = 0; iCnt < ftp.ExeTimes; iCnt++)
                            {
                                if (ftp.StopFlag)
                                {
                                    break;
                                }
                                Stopwatch sw = new Stopwatch();
                                setUploadResult(string.Format("---------第{0}个文件{1}第{2}次---------", iSort, Path.GetFileName(c), iCnt + 1));
                                var filePath = c.Replace(Path.GetFileNameWithoutExtension(c), DateTime.Now.Ticks.ToString());
                                File.Copy(c, filePath, true);
                                try
                                {
                                    sw.Start();
                                    var s2 = client.Upload(filePath, tagPath);
                                    sw.Stop();
                                    if (s2.State == RequestResultType.Fail)
                                    {
                                        setUploadResult(s2.Message);
                                    }
                                    else
                                    {
                                        setUploadResult(string.Format("文件{0}上传用时{1}分{2}秒{3}毫秒,文件大小={3})", Path.GetFileName(filePath), sw.Elapsed.Minutes, sw.Elapsed.Seconds, sw.Elapsed.Milliseconds, fileSize));
                                    }
                                    listDelFiles.Add(filePath);
                                }
                                catch (Exception ex)
                                {
                                    sw.Stop();
                                    setUploadResult(string.Format("文件{0}上传失败{1}", Path.GetFileName(filePath), ex.Message));
                                }
                            }
                            Application.DoEvents();
                        });
                    }
                    swTotal.Stop();
                    if (!isBreak)
                    {
                        setUploadResult(string.Format("一共上传{0}个源文件文件,每个文件上传{1}次用时{2}分{3}秒,总共大小={4}",
                          iTotalFile, ftp.ExeTimes, swTotal.Elapsed.Minutes, swTotal.Elapsed.Seconds, totalSize));
                    }
                    Application.DoEvents();
                    ResourceHelper.DeleFiles(listDelFiles);
                }
                Application.DoEvents();
                hideOrShowCtrl(true);
                Application.DoEvents();

            });
        }

        private void hideOrShowCtrl(bool enable)
        {
            SetControlEnable(btnStart, enable);
            SetControlEnable(txtNumber, enable);
            SetControlEnable(txtAccount, enable);
            SetControlEnable(txtPasswd, enable);
            SetControlEnable(btnFtpUsePassive, enable);
            SetControlEnable(button1, enable);
            SetControlEnable(txtIp, enable);
            SetControlEnable(txtPort, enable);

        }


        private void showInput()
        {
            btnStart.Enabled = true;
            txtNumber.Enabled = true;
            txtAccount.Enabled = true;
            txtPasswd.Enabled = true;
            btnFtpUsePassive.Enabled = true;
            button1.Enabled = true;
        }

        private void hiddenInput()
        {
            btnStart.Enabled = false;
            txtNumber.Enabled = false;
            txtAccount.Enabled = false;
            txtPasswd.Enabled = false;
            btnFtpUsePassive.Enabled = false;
            button1.Enabled = false;
        }

        delegate void SetUploadResultCallback(String str);
        public void setUploadResult(String str)
        {
            if (rtbOutput.InvokeRequired)
            {
                // 解决窗体关闭时出现“访问已释放句柄”异常
                while (rtbOutput.IsHandleCreated == false)
                {
                    if (rtbOutput.Disposing || rtbOutput.IsDisposed) return;
                }
                SetUploadResultCallback d = new SetUploadResultCallback(setUploadResult);
                rtbOutput.Invoke(d, new object[] { str });
            }
            else
            {
                StringBuilder sb = new StringBuilder();
                sb.AppendLine(str);
                rtbOutput.AppendText(sb.ToString());
            }

        }


        /// <summary>
        /// 
        /// 设置空间显示隐藏委托
        /// </summary>
        /// <param name="ctrl"></param>
        /// <param name="enable"></param>
        delegate void SetControlEnableCallback(Control ctrl, bool enable);
        public void SetControlEnable(Control ctrl, bool enable)
        {
            if (ctrl.InvokeRequired)
            {
                // 解决窗体关闭时出现“访问已释放句柄”异常
                while (ctrl.IsHandleCreated == false)
                {
                    if (ctrl.Disposing || ctrl.IsDisposed) return;
                }
                SetControlEnableCallback d = new SetControlEnableCallback(SetControlEnable);
                ctrl.Invoke(d, new object[] { ctrl, enable });
            }
            else
            {
                ctrl.Enabled = enable;
            }

        }

    }
}
